import {
  executeUpsertFoodPlan,
  queryFoodPlanByDate,
  queryFoodPlanById,
} from '@/AGC/manager/food_plan'
import { useUserStore } from '@/stores/user'
import type { UserFiltersI } from '@/types/user'
import { queryFoodFiltersNotLimit, queryFoodListByIds } from '@/AGC/manager/food'
import { Food } from '@/AGC/model/Food'
import { calculateDailyIngestion } from '@/utils/calculate_heat'
import { FoodPlan } from '@/AGC/model/FoodPlan'
import type { FoodI, FoodPlanI } from '@/types/food'
import { getFoodDislikeIdsUtil } from '@/AGC/utils/dislike'

/**
 * 更新单个饮食计划
 * @param chooseItem 用户选择的食物
 * @param choosePlan 用户选择的饮食计划
 */
export const updateSingleFoodPlanUtil = async (chooseItem: FoodI, choosePlan: FoodPlanI) => {
  const foodPlan = new FoodPlan()
  // 整合已有数据
  foodPlan.setId(choosePlan.id)
  foodPlan.setUser_id(choosePlan.user_id)
  foodPlan.setDate(choosePlan.date)
  foodPlan.setTime(choosePlan.time)
  foodPlan.setWeight(choosePlan.weight)
  // 更新食物名称
  foodPlan.setFood_name(chooseItem.name)
  // 更新食物单位
  foodPlan.setUnit(chooseItem.unit)
  // 更新食物热量
  foodPlan.setCalories((choosePlan.weight / chooseItem.weight) * chooseItem.calories)
  // 更新食物营养
  const food = new Food()
  food.setProtein(chooseItem.protein)
  food.setFat(chooseItem.fat)
  food.setCarbohydrate(chooseItem.carbohydrate)
  foodPlan.setNutrition(calculateMainNutrition(food))
  // 执行饮食计划更新
  await executeUpsertFoodPlan(foodPlan)
}

/**
 * 根据 id 获取饮食计划
 * @param id 饮食计划id
 * @returns 饮食计划
 */
export const getFoodPlanByIdUtil = async (id: number) => {
  const foodPlan = await queryFoodPlanById(id)

  if (!foodPlan) return

  return {
    id: foodPlan[0].getId(),
    user_id: foodPlan[0].getUser_id(),
    date: foodPlan[0].getDate(),
    time: foodPlan[0].getTime(),
    food_name: foodPlan[0].getFood_name(),
    weight: foodPlan[0].getWeight(),
    unit: foodPlan[0].getUnit(),
    calories: foodPlan[0].getCalories(),
    nutrition: foodPlan[0].getNutrition(),
  } as FoodPlanI
}

/**
 * 获取饮食计划列表
 * @param date 日期
 * @returns 饮食计划列表
 */
export const getFoodPlanListUtil = async (date: string) => {
  const foodPlanList = await createFoodPlanUtil(date)

  if (!foodPlanList) return []

  return foodPlanList.map((item) => {
    return {
      id: item.getId(),
      user_id: item.getUser_id(),
      date: item.getDate(),
      time: item.getTime(),
      food_name: item.getFood_name(),
      weight: item.getWeight(),
      unit: item.getUnit(),
      calories: item.getCalories(),
      nutrition: item.getNutrition(),
    } as FoodPlanI
  })
}

/**
 * 创建饮食计划
 * @param date 日期
 * @returns 饮食计划
 */
export const createFoodPlanUtil = async (date: string) => {
  // 1. 查询计划数据是否存在
  const foodPlanList = await queryFoodPlanByDate(date)

  if (foodPlanList.length > 0) return foodPlanList

  // 2. 查询食物筛选条件集合
  const foodFilters = await queryFoodFiltersNotLimit(useUserStore().userFilter as UserFiltersI)

  // 3. 查询食物集合
  if (!foodFilters.length) return

  const foodIds = foodFilters.map((item) => item.getFood_id()!)
  const foodList = await queryFoodListByIds(foodIds)

  // 4. 查询用户不喜欢的食物 ids
  const foodDislikeIds = await getFoodDislikeIdsUtil()

  // 5. 获取用户 早餐 | 午餐 | 晚餐 的食物 ids
  const breakfastIds = foodFilters
    .filter((item) => item.getBreakfast() == 1)
    .map((item) => item.getFood_id()) as number[]
  const lunchIds = foodFilters
    .filter((item) => item.getLunch() == 1)
    .map((item) => item.getFood_id()) as number[]
  const dinnerIds = foodFilters
    .filter((item) => item.getDinner() == 1)
    .map((item) => item.getFood_id()) as number[]

  // 6. 过滤用户不喜欢的食物
  const breakfastList: Food[] = filterFoodList(foodList, breakfastIds, foodDislikeIds, 3)
  const lunchList: Food[] = filterFoodList(foodList, lunchIds, foodDislikeIds, 3)
  const dinnerList: Food[] = filterFoodList(foodList, dinnerIds, foodDislikeIds, 2)

  // 5. 整合一天的饮食计划
  const result: FoodPlan[] = []
  result.push(...integrationFoodPlan(breakfastList, '早餐', date))
  result.push(...integrationFoodPlan(lunchList, '午餐', date))
  result.push(...integrationFoodPlan(dinnerList, '晚餐', date))

  // 6. 执行饮食计划插入
  await executeUpsertFoodPlan(result)

  // 7. 返回饮食计划
  return await queryFoodPlanByDate(date)
}

/**
 * 过滤食物列表
 * @param foodList 食物列表
 * @param ids 食物 id 集合
 * @param dislikeIds 用户不喜欢的食物 id 集合
 * @param num 食物数量
 * @returns 食物列表
 */
export const filterFoodList = (
  foodList: Food[],
  ids: number[],
  dislikeIds: number[],
  num: number,
) => {
  const filterIds = ids.filter((item) => !dislikeIds.includes(item))

  if (filterIds.length >= num) {
    return foodList.filter((item) => filterIds.includes(item.getId()!))
  } else {
    return foodList.filter((item) => ids.includes(item.getId()!))
  }
}

/**
 * 整合 早餐 | 午餐 | 晚餐 的食物计划
 * @param foodList 食物列表
 * @param time 时间段
 * @param date 日期
 * @returns 食物计划列表
 */
export const integrationFoodPlan = (foodList: Food[], time: string, date: string) => {
  let result: FoodPlan[] = []

  // 1. 获取每日摄入量
  let ingestion = calculateDailyIngestion(useUserStore().userFilter as UserFiltersI)

  // 2. 随机分配食物
  let randomFoodList: Food[] | undefined = []

  if (time == '早餐') {
    ingestion = ingestion * 0.3
    randomFoodList = randomFood(foodList, 3, ingestion)
    if (!randomFoodList) randomFoodList = [foodList[0], foodList[1], foodList[2]]
  } else if (time == '午餐') {
    ingestion = ingestion * 0.5
    randomFoodList = randomFood(foodList, 3, ingestion)
    if (!randomFoodList) randomFoodList = [foodList[0], foodList[1], foodList[2]]
  } else if (time == '晚餐') {
    ingestion = ingestion * 0.2
    randomFoodList = randomFood(foodList, 2, ingestion)
    if (!randomFoodList) randomFoodList = [foodList[0], foodList[1]]
  }

  // 3. 获取食物份量
  const weightStr = (
    ingestion / randomFoodList.reduce((cal, item) => cal + item.getCalories(), 0)
  ).toString()
  const weight = parseInt(weightStr)

  // 4. 整理数据
  result = randomFoodList.map((item) => {
    const foodPlan = new FoodPlan()
    foodPlan.setUser_id(useUserStore().userInfo.id)
    foodPlan.setDate(date)
    foodPlan.setTime(time)
    foodPlan.setFood_name(item.getName())
    foodPlan.setWeight(weight * item.getWeight())
    foodPlan.setUnit(item.getUnit())
    foodPlan.setCalories(weight * item.getCalories())
    foodPlan.setNutrition(calculateMainNutrition(item))
    return foodPlan
  })

  return result
}

/**
 * 随机分配食物
 * @param foodList 食物集合
 * @param num 食物数量
 * @param ingestion 每餐摄入量
 * @returns 食物集合
 */
export const randomFood = (
  foodList: Food[],
  num: number,
  ingestion: number,
): Food[] | undefined => {
  const result: Food[] | undefined = []
  let tempList = foodList

  for (let i = 0; i < num; i++) {
    result.push(tempList[Math.floor(Math.random() * tempList.length)])
    // 移除已选食物
    tempList = tempList.filter((item) => item.getId() != result[i].getId())
  }

  let totalCalories = 0

  result.forEach((item) => {
    totalCalories += item.getCalories()
  })

  if (totalCalories > ingestion + 20) {
    return randomFood(foodList, num, ingestion)
  } else {
    return result
  }
}

/**
 * 计算主要营养成分
 * @param food 食物
 * @returns 主要营养成分
 */
export const calculateMainNutrition = (food: Food) => {
  let result = ''
  const totalNutrition = food.getProtein() + food.getFat() + food.getCarbohydrate()

  if (food.getProtein() >= totalNutrition * 0.2) {
    result += '蛋白质 '
  }

  if (food.getFat() >= totalNutrition * 0.2) {
    result += '脂肪 '
  }

  if (food.getCarbohydrate() >= totalNutrition * 0.2) {
    result += '碳水化合物'
  }

  return result
}
